/**
 * 阿里云OSS上传
 */
import OSS from 'ali-oss';
import * as fs from 'node:fs';
import * as path from 'node:path';

const prefix = 'images'; // 阿里云上传后的文件夹
const toUpload = ['.images']; // 本地应上传到阿里云的文件夹

// OSS相关的权限配置和bucket地址
const client = new OSS({
  region: 'oss-cn-hangzhou',
  accessKeyId: 'LTAI5tMizqXWkZuBM8woemdu',
  accessKeySecret: 'fmZvd3ycsxtvKnB8HOW6l9IkR8gZX8',
  bucket: 'xdclass-cdn-images',
});

/**
 * 上传文件到阿里云OSS
 */
async function uploadImagesToOss() {
  // 判断本地目录是否存在的容错处理
  if (isLocalDirExists().length === 0) {
    throw new Error('本地打包目录不存在');
  }
  // 先删除阿里云的文件
  console.log('正在删除...');
  await delDirs()
    .then(() => {
      console.log('删除成功！');
    })
    .catch((err) => {
      throw new Error('删除失败:', err);
    });

  // 删除完成后上传文件
  console.log('正在上传...');
  await addFileToOSSSync(isLocalDirExists()[0], `${prefix}/`)
    .then(() => {
      console.log('oss上传成功!');
    })
    .catch((err) => {
      throw new Error('上传oss失败:', err);
    });
}

/**
 * 递归删除全部的文件（层级递归子目录）
 * @param p 要删除的文件夹名称
 */
async function delDirs(p: string = `${prefix}/`) {
  // 遍历出最初的文件列表
  let files = await client.list(
    {
      prefix: p,
      delimiter: '/',
      'max-keys': '1000',
    },
    {}
  );
  // 如果目录下存在子目录的情况下 继续递归删除子目录
  if (files.prefixes && files.prefixes.length > 0) {
    await Promise.all(files.prefixes.map(async (p) => await delDirs(p)));
  }

  // 删除当前目录下的所有文件
  await Promise.all(files.objects.map(async (o) => await handleDel(o.name)));
}

/**
 * 判断当前文件是否存在
 */
function isLocalDirExists() {
  return toUpload.filter((item) => fs.existsSync(item));
}

/**
 * 将文件上传到OSS中
 * @param src 本地目录
 * @param prefix 上传OSS的目录
 */
async function addFileToOSSSync(src: string, prefix: string) {
  // 读取出本地目录的全部文件
  let imgs = fs.readdirSync(src);
  // 递归目录逐个上传
  await Promise.all(
    imgs.map(async (item) => {
      // 输出待上传的规范的路径
      let img = path.join(src, item);
      // 返回文件路径相关信息
      let st = fs.statSync(img);

      // 如果img是个目录则需要二次递归 否则则上传
      if (st.isFile() && item !== '.DS_Store') {
        await putOSS(img, path.join(prefix, item));
      } else if (st.isDirectory()) {
        addFileToOSSSync(img, path.join(prefix, item) + '/');
      }
    })
  );
}

/**
 * 上传文件的具体方法
 * @param img 具体上传文件的本地图片位置
 * @param uploadName 上传后的相对路径和文件名
 */
async function putOSS(img: string, uploadName: string) {
  try {
    await client.put(uploadName, img);
  } catch (err) {
    throw new Error('上传失败:', err);
  }
}

/**
 * 具体的删除文件
 * @param name 待删除的文件名称
 */
async function handleDel(name: string) {
  try {
    await client.delete(name);
  } catch (err) {
    err.failObjectName = name;
    return err;
  }
}

// 执行
uploadImagesToOss();

